use crate::biliup_api::{self, VideoInfo};
use crate::get_download_list::Video;
use anyhow::{anyhow, Result};
use async_std::task::sleep;
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use log::{debug, error, info, warn};
use reqwest::header;
use reqwest::Client;
use serde_json::Value;
use std::fs;
use std::fs::remove_file;
use std::io::Write;
use std::path::Path;
use std::time::Duration;
use xmtv_api::get_video_url;
use xmtv_api::VideoUrl;

pub async fn loop_show_video(bv: &String) -> Value {
    loop {
        if let Ok(ret) = biliup_api::show_video(bv).await {
            break ret;
        }
        sleep(Duration::from_secs(60)).await;
        error!("获取{}失败", &bv);
    }
}

pub async fn fliters(videos: Vec<Video>) -> Result<Vec<Video>> {
    let mut ret = Vec::with_capacity(videos.len());

    let pb = ProgressBar::new(videos.len() as u64);
    pb.set_style(ProgressStyle::default_bar()
    .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len} ({per_sec}, {eta})")?);

    for video in videos {
        let ret_video = fliter(&video).await.unwrap();
        if !ret_video.range.is_empty() {
            ret.push(ret_video);
        }
        pb.inc(1);
    }

    pb.finish();

    Ok(ret)
}

async fn fliter(video: &Video) -> Result<Video> {
    debug!("开始确认 video = {:?}", &video);
    if video.bv.is_empty() {
        Ok(video.clone())
    } else {
        let json = loop_show_video(&video.bv).await;
        let mut per_video: Video = Video {
            title: video.title.clone(),
            bv: video.bv.clone(),
            range: Vec::with_capacity(video.range.len()),
        };
        for i in &video.range {
            let mut exists = false;
            let videos = match json["videos"].as_array() {
                Some(ret) => ret,
                None => &Vec::new(),
            };
            for j in videos.iter().rev() {
                if j["title"] == i.name {
                    exists = true;
                }
            }
            if !exists {
                per_video.range.push(i.to_owned())
            }
        }
        Ok(per_video)
    }
}

pub async fn upload_first(video: &Video, multi: Option<MultiProgress>) -> Option<String> {
    if video.bv.is_empty() {
        Some(loop {
            warn!("开始上传 {:?}", &video.range[0]);
            if let Ok(ret) = upload_video(&video.range[0], multi.clone()).await {
                break ret;
            }
        })
    } else {
        None
    }
}

pub async fn download_video(url: &str, filename: &str, multi: Option<MultiProgress>) -> Result<()> {
    let path = Path::new(&filename);
    let client = Client::new();
    let request = client.get(url);

    let mut source = request.send().await?;

    let total_size = {
        if source.status().is_success() {
            source
                .headers()
                .get(header::CONTENT_LENGTH)
                .and_then(|ct_len| ct_len.to_str().ok())
                .and_then(|ct_len| ct_len.parse().ok())
                .unwrap_or(0)
        } else {
            return Err(anyhow!("不能下载{} Error: {:?}", url, source.status(),));
        }
    };
    //println!("total_size = {}", &total_size);
    let title = filename.split("斗阵来看戏").collect::<Vec<_>>();
    let title = title[0];

    let pb = ProgressBar::new(total_size);
    let pb = match multi {
        Some(m) => m.add(pb),
        None => pb,
    };
    pb.set_style(ProgressStyle::default_bar()
    .template(format!("{{spinner:.green}} 下载{title:16} [{{elapsed_precise}}] [{{wide_bar:.cyan/blue}}] {{bytes}}/{{total_bytes}} ({{bytes_per_sec}}, {{eta}})").as_str())?);

    let mut dest = fs::File::create(path)?;
    while let Some(chunk) = source.chunk().await? {
        dest.write_all(&chunk)?;
        pb.inc(chunk.len() as u64);
    }
    Ok(())
}

pub async fn upload_video(video: &VideoUrl, multi: Option<MultiProgress>) -> Result<String> {
    let videoinfo = VideoInfo {
        title: format!("{} 斗阵来看戏", &video.title),
        copyright: 2,
        source: "https://2020.xmtv.cn/search/?search_text=斗阵来看戏".to_string(),
        tag: "戏曲,斗阵来看戏".to_string(),
        tid: 180,
        desc: "自传给家里老人看方便".to_string(),
    };
    info!("任务 video = {:?}", &video);
    let filename = format!("{}.mp4", video.name);
    debug!("下载到{:?}", &filename);
    let url = get_video_url(&video.url).await?;
    download_video(&url, &filename, multi.clone()).await?;
    debug!("任务 video = {:?} 下载到{:?}完成", &video, &filename);
    info!("开始上传 video = {:?}", &video);
    let ret = biliup_api::upload_video(videoinfo, &filename, multi).await?;
    debug!("上传完成 video = {:?}", &video);
    debug!("获取到bv号 ret = {:?}", &ret);
    remove_file(&filename)?;
    debug!("删除文件 filename = {:?}", &filename);
    Ok(ret)
}

pub async fn append_video(
    video: &VideoUrl,
    bv: &String,
    multi: Option<MultiProgress>,
) -> Result<()> {
    info!("任务 video = {:?} 上传到 bv = {:?}", &video, &bv);
    let filename = format!("{}.mp4", video.name);
    debug!("下载到{:?}", &filename);
    let url = get_video_url(&video.url).await?;
    download_video(&url, &filename, multi.clone()).await?;
    debug!("任务 video = {:?} 下载到{:?}完成", &video, &filename);
    info!("开始上传 video = {:?}", &video);
    biliup_api::append_video(&filename, bv, multi).await?;
    debug!("上传完成 video = {:?}", &video);
    remove_file(&filename)?;
    debug!("删除文件 filename = {:?}", &filename);
    Ok(())
}
